﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Schema;

namespace MIAP.Negocio.Utiles
{
    public class ValidadorXml
    {
        private StringBuilder _errorPrincipal;

        private StringBuilder _error;

        private StringBuilder _advertencias;

        private string _targetNamespace = "XMLSchemaValidacionMIAP";

        private string _rutaXSD;

        /// <summary>
        /// Total de errores encontrados
        /// </summary>
        public int TotalErrores { get; private set; }

        /// <summary>
        /// Total de advertencias encontradas
        /// </summary>
        public int TotalAdvertencias { get; private set; }

        /// <summary>
        /// cadena que contiene los errores encontrados en la validacion
        /// </summary>
        public string Errores
        {
            get
            {
                //if (!_error.ToString().Contains("</ul>"))
                //{
                //    _error.Append("</ul>");
                //}
                return _error.ToString();
            }
        }

        /// <summary>
        /// cadena con las advertencias encontradas en la validacion
        /// </summary>
        public string Advertencias
        {
            get
            {
                //if (!_advertencias.ToString().Contains("</ul>"))
                //{
                //    _advertencias.Append("</ul>");
                //}
                return _advertencias.ToString();
            }
        }

        /// <summary>
        /// Cadena con algun error en la validacion si es que ocurriera alguno
        /// </summary>
        public string ErrorPrincipal
        {
            get { return _errorPrincipal.ToString(); }
        }

        /// <summary>
        /// contructor de la clase
        /// </summary>
        /// <param name="rutaXsd">el directorio en donde se encuentra la aplicacion</param>
        public ValidadorXml(string rutaXsd)
            : this()
        {
            _rutaXSD = rutaXsd;
        }

        /// <summary>
        /// Constructor de la clase
        /// </summary>
        public ValidadorXml()
        {
            this._advertencias = new StringBuilder();
            this._error = new StringBuilder();
            this.TotalErrores = this.TotalAdvertencias = 0;
        }

        /// <summary>
        /// Comprueba si el XML cumple con las condiciones establecidas en el arhcivo XSD
        /// </summary>
        /// <param name="stringXml"></param>
        /// <returns>true si el xml es valido false en caso contrario</returns>
        public bool CompruebaXmLvsXsd(string stringXml)
        {
            try
            {
                var schemaReader = XmlReader.Create(new StreamReader(this._rutaXSD, Encoding.UTF8));
                var xmlReaderSettings = new XmlReaderSettings();
                xmlReaderSettings.Schemas.Add(this._targetNamespace, schemaReader);
                xmlReaderSettings.Schemas.Compile();
                xmlReaderSettings.ValidationEventHandler += booksSettingsValidationEventHandler;
                xmlReaderSettings.ValidationType = ValidationType.Schema;
                xmlReaderSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessIdentityConstraints;
                xmlReaderSettings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
                xmlReaderSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;

                using (var xmlReader = XmlReader.Create(new StringReader(stringXml), xmlReaderSettings))
                {
                    while (xmlReader.Read())
                    {
                    }
                }
                schemaReader.Close();
                return this.TotalAdvertencias == default(int) && this.TotalErrores == default(int);
            }
            catch (Exception ex)
            {
                this._error.Append(ex.Message);
                return false;
            }
        }

        /// <summary>
        /// Handler encargado de capturar y almacenar los errores y advertencias encontradas en la validacion
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void booksSettingsValidationEventHandler(object sender, ValidationEventArgs e)
        {
            long linea = e.Exception.LineNumber;
            long posicion = e.Exception.LinePosition;
            var stringinterno = new StringBuilder();
            if (e.Severity == XmlSeverityType.Warning)
            {
                if (String.IsNullOrEmpty(_advertencias.ToString()))
                {
                    //_advertencias.Append("<ul>");
                    //_advertencias.Append("<li type=\"square\">");
                    _advertencias.Append("Advertencias: ");
                    //_advertencias.Append("</li>");
                }
                SetMessage(e, stringinterno, linea, posicion);
                _advertencias.AppendLine(stringinterno.ToString());
                TotalAdvertencias += 1;
            }
            else if (e.Severity == XmlSeverityType.Error)
            {
                if (String.IsNullOrEmpty(_error.ToString()))
                {
                    //_error.Append("<ul>");
                    //_error.Append("<li type=\"square\">");
                    _error.Append("Errores: ");
                    //_error.Append("</li>");
                }
                SetMessage(e, stringinterno, linea, posicion);
                _error.AppendLine(stringinterno.ToString());
                TotalErrores += 1;
            }
        }

        /// <summary>
        /// Arma el mensaje del error o la excepcion 
        /// </summary>
        /// <param name="e"></param>
        /// <param name="stringinterno"></param>
        /// <param name="linea"></param>
        /// <param name="posicion"></param>
        private static void SetMessage(ValidationEventArgs e, StringBuilder stringinterno, long linea, long posicion)
        {
            //stringinterno.Append("<li type=\"disc\">");
            stringinterno.Append("    "+e.Message);
            //stringinterno.Append("</li>");
            //stringinterno.Append("<li type=\"circle\">");
            stringinterno.Append(". Linea: ");
            stringinterno.Append(linea);
            stringinterno.Append(", Posición: ");
            stringinterno.Append(posicion);
            //stringinterno.Append("</li>");
        }

    }
}
